package net.qiqbframework.config;


import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.common.Assert;

import javax.annotation.Nonnull;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 组件
 * 中使用的组件。组件描述需要创建的对象，可能基于配置中的其他组件，并作为配置的一部分进行初始化。
 * 访问组件时会延迟初始化组件。在初始化期间，它们可能会触发它们所依赖的组件的初始化。
 */
@Slf4j
public class ComponentHolder<B> {

    private final String name;
    private final Supplier<Configuration> configSupplier;
    private Function<Configuration, ? extends B> builderFunction;
    private B instance;

    public ComponentHolder(Configuration config, String name, Function<Configuration, ? extends B> builderFunction) {
        this(() -> config, name, builderFunction);
    }


    public ComponentHolder(@Nonnull Supplier<Configuration> config,
                           @Nonnull String name,
                           @Nonnull Function<Configuration, ? extends B> builderFunction) {
        this.configSupplier = config;
        this.name = name;
        this.builderFunction = builderFunction;
    }


    public B get() {
        if (instance == null) {
            return doGet();
        }
        return instance;
    }

    private synchronized B doGet() {
        if (instance == null) {
            Configuration configuration = configSupplier.get();
            instance = builderFunction.apply(configuration);
            log.debug("Instantiated component [{}]: {}", name, instance);
            LifecycleHandlerInspector.registerLifecycleHandlers(configuration, instance);
        }
        return instance;
    }


    public void update(@Nonnull Function<Configuration, ? extends B> builderFunction) {
        Assert.state(instance == null, () -> "Cannot change " + name + ": it is already in use");
        this.builderFunction = builderFunction;
    }

    public boolean isInitialized() {
        return instance != null;
    }
}
